/*
Copyright (c) [2019年5月1日] [吴超]
[MBT_studio] is licensed under Mulan PSL v2.
You can use this software according to the terms and conditions of the Mulan PSL v2.
You may obtain a copy of Mulan PSL v2 at:
		 http://license.coscl.org.cn/MulanPSL2
THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
See the Mulan PSL v2 for more details.
*/
#include "stdafx.h"
#include "S_摄像机.h"

#include "数学/数学.h"
#include "底层绘图/底层绘图框架.h"
#include <matXX.h>



inline Mat44 f_构建摄像机视图矩阵(S_摄像机& camera, Mat44f* 父级变换) {
	
	auto mat = f_构建移动矩阵({0.0f, 0.0f, camera.m_视点距离});
	auto rx = RotationMatrix(M_角度转弧度(camera.m_变换.rotation.x), { 1.0f,0.0f,0.0f });
	auto ry = RotationMatrix(M_角度转弧度(camera.m_变换.rotation.y), { 0.0f,1.0f,0.0f });
	auto s = ScaleMatrix({ camera.m_缩放.x, camera.m_缩放.y, camera.m_缩放.z });
	//auto s = ScaleMatrix({ camera.m_变换.scale.x, camera.m_变换.scale.y, camera.m_变换.scale.z });
	
	vec3 eyey_offset = camera.m_眼睛偏移;
	if (camera.m_投影模式 == E_投影模式::e_透视) {
		eyey_offset = camera.m_眼睛偏移;
	}
	else {
		eyey_offset = vec_反向(camera.m_眼睛偏移);
	}
	auto offset = f_构建移动矩阵({ eyey_offset.x, eyey_offset.y, eyey_offset.z });
	auto offset视点 = f_构建移动矩阵(camera.m_视点);


	/*auto mat = f_mat44_构建移动矩阵({0.0f, 0.0f, camera.m_视点距离});
	auto rx = f_mat44_构建行式旋转矩阵({ 1.0f,0.0f,0.0f }, M_角度转弧度(camera.m_变换.rotation.x));
	auto ry = f_mat44_构建行式旋转矩阵({ 0.0f,1.0f,0.0f }, M_角度转弧度(camera.m_变换.rotation.y));
	auto s = f_mat44_构建缩放矩阵(camera.m_缩放);
	auto offset = f_mat44_构建移动矩阵(eyey_offset);
	auto offset视点 = f_mat44_构建移动矩阵(camera.m_视点);*/


	camera.m_相机位置矩阵 = mat * offset * (rx * ry) * s * offset视点;
	//if (父级变换) {
	//	camera.m_相机位置矩阵 = *(Mat44*)父级变换 * camera.m_相机位置矩阵;
	//}
	//camera.m_变换.location = (f_mat44_Inverse(camera.m_相机位置矩阵) * vec3 { 0, 0, 0 });
	auto 逆矩阵 = f_逆矩阵(camera.m_相机位置矩阵);
	
	camera.m_变换.location = (逆矩阵 * vec3 { 0, 0, 0 });

	
	return mat;
}




S_摄像机::S_摄像机(S_设备环境& ctx) : m_Ctx(ctx), S_物体(E_物体类型::t_摄像机){
	m_相机矩阵.resize(2);

	m_分辨率    = { 1920,1080 };
	m_宽高比	= 1.0;
	m_视角		= 45.0;


	m_眼睛偏移	= { 0,0,0 };
	m_视点		= { 10.0f,0.0f,0.0f };
	m_视点距离	= -20.0;

	m_近远端	= { 0.05f, 1000.0f };
	m_投影模式	= E_投影模式::e_透视;
	m_缩放 = { 1.0f,-1.0f, -1.0f };
}

void S_摄像机::f_LookAt(const vec3& eye, const vec3& t, const vec3& up) {
	m_视点 = t;
	m_变换.location = eye;

	vec3 眼睛 = m_变换.location + m_眼睛偏移;
	vec3 视点 = m_视点 + m_眼睛偏移;

	m_上方向 = up;
	//m_相机位置矩阵 = *(Mat44f*)&f_LookAtMatrix({ 眼睛.x, 眼睛.y, 眼睛.z }, { 视点.x, 视点.y, 视点.z }, { m_上方向.x, m_上方向.y, m_上方向.z });
	m_相机位置矩阵 = f_LookAtMatrix({ 眼睛.x, 眼睛.y, 眼睛.z }, { 视点.x, 视点.y, 视点.z }, { m_上方向.x, m_上方向.y, m_上方向.z } );
	
	m_isUpdate = true;
}

void S_摄像机::f_set透视投影(float32 角度, float32 宽高比, const vec2& 近远端) {
	m_视角 = 角度;
	m_宽高比 = 宽高比;
	m_近远端 = 近远端;
	
	m_isUpdate = true;
}

void S_摄像机::f_set正交投影(const vec2& size) {
	m_相机投影 = f_OrthographicMatrix(0, size.x, size.y, 0, 0, 1000);
	m_投影模式 = E_投影模式::e_正交;
	//m_正交边界.x = 1;
	//m_正交边界.y = size.y / size.x;
	m_正交边界 = size*0.01f;

	m_isUpdate = true;
}




void S_摄像机::f_set位置(float32 x, float32 y, float32 z) {

}

void S_摄像机::f_set累加旋转(float32 x, float32 y, float32 z) {
	m_变换.rotation.x += x;
	m_变换.rotation.y += y;
	m_变换.rotation.z += z;


	auto mat = f_构建摄像机视图矩阵(*this, nullptr);

	m_isUpdate = true;
}

void S_摄像机::f_set缩放(float32 x, float32 y, float32 z) {
	//vec3 s = m_相机投影 * vec3({ 0.0f, 0.0f, m_视点距离 });
	//std::cout << s.z << " = " << x << std::endl;
	m_视点距离 -= m_视点距离*x*0.12;
	m_视点距离 = DEF_Min(m_视点距离, -0.01);
	auto mat = f_构建摄像机视图矩阵(*this, nullptr);

	m_isUpdate = true;
}

void S_摄像机::f_set视点偏移(vec3 offset) {
	m_眼睛偏移 = offset;
	std::cout << "B 眼睛偏移 = " << m_眼睛偏移.x << " : " << m_眼睛偏移.y << " : " << m_眼睛偏移.z << std::endl;
	m_isUpdate = true;
}







void S_摄像机::f_set视角(float32 r) {
	m_视角 = r;
	m_isUpdate = true;
}

void S_摄像机::f_set宽高比(vec2 view) {
	//m_宽高比 = DEF_Min(view.x, view.y) / DEF_Max(view.x, view.y);
	m_宽高比 = view.x / view.y;
	m_isUpdate = true;
}

void S_摄像机::f_Update(Mat44f* c) {
	
	if (m_投影模式 == E_投影模式::e_透视) {
		m_相机投影 = ProjectionMatrix(m_视角, m_宽高比, m_近远端.x, m_近远端.y);
		m_缩放 = { 1.0f,-1.0f, -1.0f };
		//m_缩放 = { 1.0f, 1.0f, 1.0f };
	}
	else {
		m_相机投影 = f_OrthographicMatrix(
			-m_视点距离 * 0.5 * m_宽高比, 
			m_视点距离 * 0.5 * m_宽高比, 
			-m_视点距离 * 0.5, 
			m_视点距离 * 0.5, 
			10000, -1000);
		//m_相机投影 = f_OrthographicMatrix(m_眼睛偏移.x, m_视点距离, m_视点距离, 0, 0, 100);
		m_缩放 = { -1.0f, 1.0f, 1.0f };
	}

	f_构建摄像机视图矩阵(*this, c);
	//m_相机位置矩阵 = f_LookAtMatrix({ 眼睛.x, 眼睛.y, 眼睛.z }, { 视点.x, 视点.y, 视点.z }, { m_上方向.x, m_上方向.y, m_上方向.z });

	//m_相机矩阵[0] = *((Mat44f*)m_相机投影.columns);
	/*m_相机位置 = f_LookAtMatrix({ m_眼睛.x, m_眼睛.y, m_眼睛.z },
								{ m_视点.x, m_视点.y, m_视点.z },
								{ m_上方向.x,m_上方向.y,m_上方向.z }
	);*/

	std::vector<Mat44f> mat(4);
	
	Mat44 MVP;
	//Mat4X4_相乘(&mat[0], &m_相机矩阵[1], &m_相机矩阵[0]);
	MVP = m_相机投影 * m_相机位置矩阵;
	//auto rx = RotationMatrix(M_角度转弧度(m_缩放.z * m_变换.rotation.x), { 1.0f,0.0f,0.0f });
	//auto ry = RotationMatrix(M_角度转弧度(m_缩放.z * m_变换.rotation.y * -1), { 0.0f,1.0f,0.0f });
	
	auto rx = RotationMatrix(M_角度转弧度(m_变换.rotation.x), { 1.0f,0.0f,0.0f });
	auto ry = RotationMatrix(M_角度转弧度(m_变换.rotation.y), { 0.0f,1.0f,0.0f });
	//auto s = ScaleMatrix({ m_缩放.x, m_缩放.y, m_缩放.z });

	mat[0] = *((Mat44f*)&MVP);
	//MVP = f_逆矩阵((rx * ry));
	//MVP = f_逆矩阵(ry * rx);
	if (m_投影模式 == E_投影模式::e_透视) {
		auto s = ScaleMatrix({ -m_缩放.x, -m_缩放.y, -m_缩放.z });
		MVP = ((rx * ry) * s);
	}
	else {
		auto s = ScaleMatrix({ m_缩放.x, m_缩放.y, m_缩放.z });
		MVP = ((rx * ry) * s);
	}
	mat[1] = *((Mat44f*)&(MVP));
	mat[2] = *((Mat44f*)&(m_相机投影));
	mat[3] = *((Mat44f*)&(m_相机位置矩阵));
	
	f_fill板载缓存(m_投影矩阵, mat, E_板载缓存类型::e_UBO, m_Ctx);

	//S_物体::f_Update(c, 父级变换);
	m_isUpdate = false;
}

void S_摄像机::f_绘制() {

}

Mat44f f_camera_计算旋转矩阵(const S_摄像机& camera, bool 是否逆) {
	Mat44f mat;

	auto rx = RotationMatrix(M_角度转弧度(camera.m_变换.rotation.x), { 1.0f,0.0f,0.0f });
	auto ry = RotationMatrix(M_角度转弧度(camera.m_变换.rotation.y), { 0.0f,1.0f,0.0f });
	

	auto t = (rx * ry);

	if (camera.m_投影模式 == E_投影模式::e_透视) {
		auto s = ScaleMatrix({ camera.m_缩放.x, camera.m_缩放.y, camera.m_缩放.z });
		t *= s;
	}
	else {
		auto s = ScaleMatrix({ -camera.m_缩放.x, -camera.m_缩放.y, -camera.m_缩放.z });
		t *= s;
	}

	if (是否逆) {
		t = f_逆矩阵(t);
	}
	mat = *((Mat44f*) & t);

	return mat;
}
